package TimeHelper

import (
	"errors"
	"fmt"
	"math"
	"strings"
	"time"
)

var TIME_ERROR_ZERO = errors.New("empty time")

const (
	ANSIC                  = "Mon Jan _2 15:04:05 2006"
	UnixDate               = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate               = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822                 = "02 Jan 06 15:04 MST"
	RFC822Z                = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	RFC850                 = "Monday, 02-Jan-06 15:04:05 MST"
	RFC1123                = "Mon, 02 Jan 2006 15:04:05 MST"
	RFC1123Z               = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	RFC3339                = "2006-01-02T15:04:05Z07:00"
	RFC3339Nano            = "2006-01-02T15:04:05.999999999Z07:00"
	Kitchen                = "3:04PM"
	Stamp                  = "Jan _2 15:04:05"
	StampMilli             = "Jan _2 15:04:05.000"
	StampMicro             = "Jan _2 15:04:05.000000"
	StampNano              = "Jan _2 15:04:05.000000000"
	UTFALL_SECOND          = "2006-01-02 15:04:05"
	UTFALL_MINUTE          = "2006-01-02 15:04"
	UTFALL_HOUR_UNDERLINE  = "2006_01_02_15"
	UTFALL_HOUR            = "2006-01-02 15"
	UTFALL_DATE_UNDERLINE  = "2006_01_02"
	UTFALL_DATE            = "2006-01-02"
	UTFMONTH               = "2006-01"
	TTFALL_DATE_INT        = "20060102"
	UTFALL_DATE_INT_SECOND = "20060102150405"
)

type TimeHelper struct {
	time time.Time
}

var cstZone = time.FixedZone("CST", 8*3600)

type TimeWeek struct {
	Year    int
	Month   int
	Weekday int
}

func GetCstZone() *time.Location {
	return cstZone
}

/**
时间格式初始化
*/
func NewTime(time time.Time) *TimeHelper {
	time.In(cstZone)
	return &TimeHelper{time: time}
}

func NewNowTime() *TimeHelper {
	return &TimeHelper{time: time.Now().In(cstZone)}
}

/**
获取时间 time
*/
func (t *TimeHelper) GetTime() time.Time {
	return t.time
}

/**
获取年
*/
func (t *TimeHelper) GetYear() int {
	return t.time.Year()
}

/**
获取月
*/
func (t *TimeHelper) GetMonth() int {
	return int(t.time.Month())
}

/**
获取天
*/
func (t *TimeHelper) GetDay() int {
	return t.time.Day()
}

/**
获取小时
*/
func (t *TimeHelper) GetHour() int {
	return t.time.Hour()
}

/**
获取分
*/
func (t *TimeHelper) GetMinute() int {
	return t.time.Minute()
}

/**
获取秒
*/
func (t *TimeHelper) GetSecond() int {
	return t.time.Second()
}

/**
获取星期
*/
func (t *TimeHelper) GetWeekDay() *TimeWeek {
	return t.WeekByDate(t.time)
}

/**
返回时间字符串
2021-12-21 23:59:59
*/
func (t *TimeHelper) ToAll() string {
	return t.time.Format(UTFALL_SECOND)
}

/**
获取日期字符串
2021-12-21
*/
func (t *TimeHelper) ToDate() string {
	return t.time.Format(UTFALL_DATE)
}

/**
获取时间毫秒
*/
func (t *TimeHelper) ToMillisecond() int64 {
	if t.time.IsZero() {
		return 0
	}
	return t.time.UnixNano() / 1e6
}

/**
获取日期字符串(无符号)
20220320
*/
func (t *TimeHelper) ToDateIntStr() string {
	return t.time.Format(TTFALL_DATE_INT)
}

/**
获取当前时间字符串(精到秒 无符号)
*/
func (t *TimeHelper) ToDateSecondIntStr() string {
	return t.time.Format(UTFALL_DATE_INT_SECOND)
}

/**
获取日期字符串，用下划线分隔
2021_12_21
*/
func (t *TimeHelper) ToDateUnderLine() string {
	return t.time.Format(UTFALL_DATE_UNDERLINE)
}

/**
获取小时
2021-12-21 23
*/
func (t *TimeHelper) ToHour() string {
	return t.time.Format(UTFALL_HOUR)
}

/**
获取小时，用下划线分隔
2021_12_21_23
*/
func (t *TimeHelper) ToHourUnderLine() string {
	return t.time.Format(UTFALL_HOUR_UNDERLINE)
}

/**
获取分
2021-12-21 23:59
*/
func (t *TimeHelper) ToMinute() string {
	return t.time.Format(UTFALL_MINUTE)
}

/**
返回时间秒戳
*/
func (t *TimeHelper) ToUnix() int64 {
	return t.time.Unix()
}

/**
获取上个月[月] 返回time
[逻辑]
1. 根据传入time 获取当前时间
2. 传day 获取间隔的天数, 如:
   1) 当前时间为: 2022-03-06, day: 1 则返回 2022-02-06
   2) 当前时间为: 2022-03-06, day: -1 赠返回 2022-02-06
@param month int 正负整数
*/
func (t *TimeHelper) GetSubMonthTime(month int) time.Time {
	return AddDate(t.time, 0, month, 0)
}

/**
获取时间指定差积的时间[月]
[逻辑]
1. 根据传入time 获取当前时间
2. 传day 获取间隔的天数, 如:
   1) 当前时间为: 2022-03, day: 1 则返回 2022-02
   2) 当前时间为: 2022-03, day: -1 赠返回 2022-02
@param day int 正负整数
*/
func (t *TimeHelper) GetSubMonth(month int) string {
	n := t.GetSubMonthTime(month)
	return n.Format(UTFMONTH)
}

/**
获取第二天的指定小时

如当前为2022-03-20 12:00:00
传入hour 后 如：3
获取到的值为 2022-03-21 03:00:00

@param hour int 指定小时, 24小时制
*/
func (t *TimeHelper) GetNextDayHour(hour int) *TimeHelper {

	// 计算下一个零点
	next := t.time.Add(time.Hour * 24)
	next = time.Date(next.Year(), next.Month(), next.Day(), hour, 0, 0, 0, next.Location())
	//next := now.Add(time.Millisecond*5000)
	//next = time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), next.Minute(), next.Second(),next.Nanosecond(), next.Location())
	//fmt.Println("xxx2", next)
	//timeDuration = next.Sub(te)
	return NewTime(next)
}

/**
获取时间指定差积的时间[天]
[逻辑]
1. 根据传入time 获取当前时间
2. 传day 获取间隔的天数, 如:
   1) 当前时间为: 2022-03-24, day: 1 则返回 2022-03-25
   2) 当前时间为: 2022-03-24, day: -1 赠返回 2022-03-23
@param day int 正负整数

*/
func (t *TimeHelper) GetSubDay(day int) string {
	n := t.GetSubDayTime(day)
	return n.Format(UTFALL_DATE)
}

/**
获取时间返回 时间戳
[逻辑]
1. 根据传入time 获取当前时间
2. 传day 获取间隔的天数, 如:
   1) 当前时间为: 2022-03-24, day: 1 则返回 2022-03-25 这里为time.Time
   2) 当前时间为: 2022-03-24, day: -1 赠返回 2022-03-23 这里为time.Time
@param day int 正负整数
*/
func (t *TimeHelper) GetSubDayTime(day int) time.Time {
	//n := t.time.AddDate(0, 0, day)
	return AddDate(t.time, 0, 0, day)
}

/**
获取距离下一天指定小时还有多少时间
如当前为2022-03-20 00:10:00
传入hour 后 如：3
返回为 26h50m0s

@param hour int 指定小时, 24小时制
*/
func (t *TimeHelper) GetNextDayHourTimeDuration(hour int) time.Duration {
	te := t.GetNextDayHour(hour)
	return te.time.Sub(t.time)
}

/**

 */
func (t *TimeHelper) WeekByDate(time time.Time) *TimeWeek {
	yearDay := time.YearDay()
	yearFirstDay := AddDate(time, 0, 0, -yearDay+1)
	firstDayInWeek := int(yearFirstDay.Weekday())

	//今年第一周有几天
	firstWeekDays := 1
	if firstDayInWeek != 0 {
		firstWeekDays = 7 - firstDayInWeek + 1
	}
	var week int
	if yearDay <= firstWeekDays {
		week = 1
	} else {
		week = (yearDay-firstWeekDays)/7 + 2
	}
	weekDay := &TimeWeek{
		Year:    time.Year(),
		Month:   int(time.Month()),
		Weekday: week,
	}
	return weekDay
}

/**
获取当前时间
*/
func GetNowTime() time.Time {
	return time.Now().In(cstZone)
}

/**
获取当前时间字符串
2021-12-21 23:59:59
*/
func GetNowTimeStr() string {
	return NewTime(GetNowTime()).ToAll()
}

/**
解析时间字符串到时间戳
@param timeStr string   时间字符串：2021-12-21 23:59:59
*/
func TimePare(timeStr string) (time.Time, error) {
	return time.ParseInLocation(UTFALL_SECOND, timeStr, cstZone)
}

/**
解析秒级时间戳到日期
*/
func TimeParseUnixSecondToDate(unixTime int64) (*TimeHelper, error) {
	tm := time.Unix(unixTime, 0)
	if tm.IsZero() {
		return nil, TIME_ERROR_ZERO
	}
	return NewTime(tm), nil
}

/**
解析时间日期字符串到时间戳
@param s string 时间日期字符串 : 2022-05-16
*/
func TimeParseDate(s string) (time.Time, error) {
	return time.ParseInLocation(UTFALL_DATE, s, cstZone)
}

/**
解析日期字符串到时间戳
@param s string 日期字符串: 2022-05
*/
func TimeParseMonth(s string) (time.Time, error) {
	return time.ParseInLocation(UTFMONTH, s, cstZone)
}

/**
无字符串分隔
解析时间日期字符串到时间戳
@param string 时间日期字符串 : 20220516
*/
func TimeParseDateUnSeparator(s string) (time.Time, error) {
	return time.ParseInLocation(TTFALL_DATE_INT, s, cstZone)
}

/**
获取当前时间日期
2021-12-21
*/
func GetNowTimeDate() string {
	return NewTime(GetNowTime()).ToDate()
}

/**
获取当前时间日期，用下划线分隔
2021_12_21
*/
func GetNowTimeDateUnderline() string {
	return NewTime(GetNowTime()).ToDateUnderLine()
}

/**
获取当前时间  日期+小时，用下划线分隔
2021_12_21_23
*/
func GetNowTimeHourUnderline() string {
	return NewTime(GetNowTime()).ToHourUnderLine()
}

/**
获取与当前时间计算后的值并返回字符串
2021-12-21 23:59:59
*/
func GetArbitrarilyTimeStr(increment time.Duration) string {
	return time.Now().In(cstZone).Add(increment).Format(UTFALL_SECOND)
}

/**
时间过去计算
解析字符串日期格式 ：Y-m-d H:i:s
*/
func OverFormatTime(formatTime string) string {
	if strings.Trim(formatTime, " ") == "" {
		return ""
	}
	timeLong, err := TimePare(formatTime)
	if err != nil {
		return ""
	}
	var timeOverFormat string

	nowTime := GetNowTime()
	diffTime := nowTime.Sub(timeLong).Seconds()
	if diffTime < 60 {
		timeOverFormat = "刚刚"
	} else if diffTime < 3600 {
		min := int64(math.Floor(diffTime / 60))
		timeOverFormat = fmt.Sprintf("%d分钟前", min)
	} else if diffTime < 86400 {
		min := int64(math.Floor(diffTime / 3600))
		timeOverFormat = fmt.Sprintf("%d小时前", min)
	} else if diffTime < 864003 {
		min := int64(math.Floor(diffTime / 86400))
		if min == 1 {
			timeOverFormat = "昨天"
		} else {
			timeOverFormat = "前天"
		}
	} else {
		timeOverFormat = formatTime
	}

	return timeOverFormat
}

/**
获取两个日期间隔的日期明细
@param startDate string [true] 开始日期 [如：2022-06-14]
@param endDate   string [true] 结束日期 [如：2022-06-16]

@return []string{}  exp: []string{2022-06-14, 2022-06-15, 2022-06-16}
*/
func GetTimeDatePartition(startDate string, endDate string) ([]string, error) {
	startDateTime, err := TimeParseDate(startDate)
	if err != nil {
		return nil, errors.New("parse start date error")
	}
	endDateTime, err := TimeParseDate(endDate)

	if err != nil {
		return nil, errors.New("parse end date error")
	}

	if startDateTime.IsZero() {
		return nil, errors.New("start date error")
	}

	if endDateTime.IsZero() {
		return nil, errors.New("end date error")
	}

	if endDateTime.Before(startDateTime) {
		return nil, errors.New("end date master be big than start date")
	}
	allTime := []string{}
	//endDateTime 需要加一天， 将当前时间统计到里面
	endDateTime = AddDate(endDateTime, 0, 0, 1)
	for endDateTime.After(startDateTime) {
		itemHelper := NewTime(startDateTime)
		allTime = append(allTime, itemHelper.ToDate())
		startDateTime = AddDate(startDateTime, 0, 0, 1)
	}
	return allTime, nil
}

/**
当前时间当前月的开始与结束日期
*/
func GetTimeDateMonthBeginAndEnd(times time.Time) ([]string, error) {
	if times.IsZero() {
		return nil, errors.New("date time error")
	}
	startTime := times.AddDate(0, 0, -times.Day()+1)
	endTime := startTime.AddDate(0, 1, -1)

	rt := make([]string, 2)
	startTimeStr := NewTime(startTime).ToDate()
	endTimeStr := NewTime(endTime).ToDate()
	rt[0] = startTimeStr
	rt[1] = endTimeStr
	return rt, nil
}

/**
获取当前时间的日期
如： 2022_11_01
*/
func GetNowDayTimeStrUnderline() string {
	return time.Now().In(cstZone).Format("2006_01_02")
}

/**
获取当前时间的日期
如: 2022-11-01
*/
func GetNowDayTimeStr() string {
	return time.Now().In(cstZone).Format(UTFALL_DATE)
}

/**
获取昨天的日期
如：
当前时间为 2022-11-01
则返回：2022_10_31
*/
func GetLastDayTimeStrUnderline() string {
	year, month, day := time.Now().In(cstZone).Date()
	thisMonth := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
	return AddDate(thisMonth, 0, 0, -1).Format("2006_01_02")
}

/**
返回两个日期相差几个月
@param max time.Time
@param min time.Time
*/
func GetSubMonthDiffer(max, min time.Time) (month int) {
	y1 := max.Year()
	y2 := min.Year()
	m1 := int(max.Month())
	m2 := int(min.Month())
	d1 := max.Day()
	d2 := min.Day()

	yearInterVal := y1 - y2
	//如果d1的月-日小于d2的月-日 yearInterval-- 这样就得到了相相差的年数
	if m1 < m2 || m1 == m2 && d1 < d2 {
		yearInterVal--
	}

	//获取月数差值
	monthInterval := (m1 + 12) - m2
	if d1 < d2 {
		monthInterval--
	}
	monthInterval %= 12
	month = yearInterVal*12 + monthInterval
	return
}
